use std::fs;

use colored::Colorize;
use tree_sitter::Parser;

pub mod go_parser;
pub mod java_parser;
pub mod javascript_parser;
pub mod vue_parser;
pub mod rust_parser;

pub trait Language_Parser {
    fn filter(&self, file_name: &String) -> bool;
    fn get_tree_sitter(&self) -> Parser;
    fn find_functions(&self, file_path: String) -> Vec<String> {
        let mut parser = self.get_tree_sitter();

        // 读取代码
        let content = fs::read_to_string(&file_path.as_str()).expect("java file not exists");
        let content = content.as_str();

        // 解析
        let java_tree = parser.parse(content, None).unwrap();

        // 遍历查找
        let mut funcs: Vec<String> = Vec::new();
        let root_node: tree_sitter::Node<'_> = java_tree.root_node();
        let mut cursor: tree_sitter::TreeCursor<'_> = root_node.walk();
        cursor.goto_first_child();
        'outer: loop {
            let current_node = cursor.node();
            if current_node.kind() == "method_declaration"
                || current_node.kind() == "function_declaration"
            {
                let func_code = &content[current_node.start_byte()..current_node.end_byte()];
                funcs.push(func_code.to_string());
            }

            if cursor.goto_first_child() {
                continue;
            }

            if cursor.goto_next_sibling() {
                continue;
            }

            loop {
                if !cursor.goto_parent() {
                    break 'outer;
                }

                if !cursor.goto_next_sibling() {
                    continue;
                }
                break;
            }

            continue;
        }

        return funcs;
    }
}

pub fn by_file_name(file_path: String) -> Option<Box<dyn Language_Parser>> {
    let parser_list: Vec<Box<dyn Language_Parser>> = vec![
        Box::new(java_parser::Java_Parser {}),
        Box::new(go_parser::Go_Parser {}),
        Box::new(javascript_parser::JavaScript_Parser {}),
        Box::new(vue_parser::Vue_Parser {}),
    ];
    for parser in parser_list {
        if parser.filter(&file_path) {
            return Some(parser);
        }
    }
    return None;
}
